<template>
	<div
		class="v-input"
		:class="[
			{
				disabled: disabled,
				'password-icon': showPassword,
			},
		]"
	>
		<input
			ref="input"
			v-if="type !== 'textarea'"
			v-bind="$attrs"
			class="v-input_inner"
			:type="showPassword ? (passwordVisible ? 'text' : 'password') : type"
			:placeholder="placeHolder"
			:readonly="readonly"
			:disabled="disabled"
			@input="handleInput"
			@focus="handleFocus"
			@blur="handleBlur"
			@change="handleChange"
		/>
		<textarea
			ref="textarea"
			v-else
			class="v-textarea_inner"
			:style="textareaCalcStyle"
			v-bind="$attrs"
			:placeholder="placeHolder"
			:disabled="disabled"
			:readonly="readonly"
			@input="handleInput"
			@focus="handleFocus"
			@blur="handleBlur"
			@change="handleChange"
		>
		</textarea>
		<span ref="inputIcon" class="v-input_icon flex" :style="inputIconStyle">
			<svg
				@click="handlePasswordVisible"
				v-if="showPwdVisible"
				class="icon"
				aria-hidden="true"
			>
				<use xlink:href="#v-iconchakan" />
			</svg>
			<svg
				@click="clear"
				v-if="showClear"
				class="icon clear"
				aria-hidden="true"
			>
				<use xlink:href="#v-iconqingchu" />
			</svg>
			<span v-if="isWordLimitVisible" class="v-input_count">
				{{ textLength }}/{{ upperLimit }}
			</span>
		</span>
	</div>
</template>
<script>
import "./icon/iconfont.js";
import calcTextareaHeight from "./calcTextareaHeight";
export default {
	name: "VInput",
	inheritAttrs: false,
	data() {
		return {
			passwordVisible: false,
			focused: false,
			textareaCalcStyle: {},
			inputIconStyle: {},
		};
	},
	props: {
		placeHolder: String,
		value: [String, Number],
		disabled: Boolean,
		readonly: Boolean,
		type: {
			type: String,
			default: "text",
		},
		showPassword: {
			type: Boolean,
			default: false,
		},
		clearable: {
			type: Boolean,
			default: false,
		},
		autosize: {
			type: [Boolean, Object],
			default: false,
		},
		showWordLimit: {
			type: Boolean,
			default: false,
		},
	},
	computed: {
		model() {
			return this.value;
		},
		showPwdVisible() {
			return (
				this.showPassword &&
				!this.disabled &&
				!this.readonly &&
				(!!this.nativeInputValue || this.focused)
			);
		},
		nativeInputValue() {
			return this.value === null || this.value === undefined
				? ""
				: String(this.value);
		},
		showClear() {
			return (
				this.clearable &&
				!this.disabled &&
				!this.readonly &&
				this.nativeInputValue
			);
		},
		upperLimit() {
			return this.$attrs.maxlength;
		},
		textLength() {
			if (typeof this.value === "number") {
				return String(this.value).length;
			}
			return (this.value || "").length;
		},
		isWordLimitVisible() {
			return (
				this.showWordLimit &&
				this.$attrs.maxlength &&
				(this.type === "text" || this.type === "textarea") &&
				!this.disabled &&
				!this.readonly &&
				!this.showPassword
			);
		},
	},
	watch: {
		value() {
			this.$nextTick(this.resizeTextarea);
			this.setInpPadding();
		},
		nativeInputValue() {
			this.setNativeInputValue();
		},
		type() {
			this.$nextTick(() => {
				this.setNativeInputValue();
				this.resizeTextarea();
			});
		},
	},
	mounted() {
		this.setNativeInputValue();
		this.resizeTextarea();
		this.setInputIconPosition();
	},
	methods: {
		focus() {
			this.getInput().focus();
		},
		blur() {
			this.getInput().blur();
		},
		handlePasswordVisible() {
			this.passwordVisible = !this.passwordVisible;
			this.$nextTick().then(() => {
				this.focus();
			});
		},
		clear() {
			this.$emit("input", "");
			this.$emit("change", "");
			this.$emit("clear");
		},
		handleFocus(event) {
			this.focused = true;
			this.$emit("focus", event);
		},
		handleBlur(event) {
			this.focused = false;
			this.$emit("blur", event);
		},
		handleChange(event) {
			this.$emit("change", event.target.value);
		},
		resizeTextarea() {
			const { autosize, type } = this;
			if (type !== "textarea") return;
			if (!autosize) {
				this.textareaCalcStyle = {
					minHeight: calcTextareaHeight(this.$refs.textarea).minHeight,
				};
				return;
			}
			const minRows = autosize.minRows;
			const maxRows = autosize.maxRows;
			this.textareaCalcStyle = calcTextareaHeight(
				this.$refs.textarea,
				minRows,
				maxRows
			);
		},
		setInputIconPosition() {
			const style = {
				top: "calc(100% - 8px)",
				transform: "translateY(-100%)",
			};
			this.inputIconStyle = style;
		},
		getInput() {
			return this.$refs.input || this.$refs.textarea;
		},
		setNativeInputValue() {
			const input = this.getInput();
			if (!input) return;
			if (input.value === this.nativeInputValue) return;
			input.value = this.nativeInputValue;
		},
		handleInput(event) {
			if (event.target.value === this.nativeInputValue) return;
			this.$emit("input", event.target.value);
			this.$nextTick(this.setNativeInputValue);
		},
		setInpPadding() {
			const setPadding =
				this.showPassword || this.clearable || this.showWordLimit;
			if (!setPadding || this.type == "textarea") return;
			this.getInput().style.paddingRight =
				this.$refs.inputIcon.clientWidth + 13 + "px";
		},
	},
};
</script>
